package com.yc.blog.jpa;

import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.yc.entity.Clazz;
import com.yc.entity.Grade;
import com.yc.entity.Student;

public class SimpleJpaTest {
	private EntityManagerFactory entityManagerFactory;
	private EntityManager entityManager;
	private EntityTransaction transaction;

	@Before
	public void init() {
		/**
		 * 通过Persistence获取EntityManagerFactory， 传入参数对应配置文件中持久化单元persistence-unit的name
		 * 通过EntityManagerFactory创建EntityManager 获取EntityTransaction 开启事务
		 */
		entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
		entityManager = entityManagerFactory.createEntityManager();
		transaction = entityManager.getTransaction();
		transaction.begin();
	}

	@After
	public void distory() {
		/**
		 * 提交事务 关闭entityManager 关闭entityManagerFactory
		 */
		transaction.commit();
		entityManager.close();
		entityManagerFactory.close();
	}
	
//	//--------简单的增删改查(CURD)--------
//	@Test
//	public void testSimpleCreate() {
//	  Clazz clz1 = new Clazz();
//      clz1.setName("计科1601");
//      clz1.setDate(new Date());
//      
//      Student stu1 = new Student();
//      stu1.setName("mary");
//      stu1.setTel("18866005544");
//      stu1.setDate(new Date());
//      stu1.setClazz(clz1);
//      
//      entityManager.persist(clz1);
//      entityManager.persist(stu1);
//	}
//	
//	@Test
//	public void testSimpleUpdate() {
//    Clazz clazz = entityManager.find(Clazz.class, 5);
//    Set<Student> stus = clazz.getStus();
//    for (Student st : stus) {
//		System.out.println(st.getName());
//	}
//	}
//
//	@Test
//	public void testSimpleRead() {
//		Student student = entityManager.find(Student.class, 1);
//		System.out.println(student.getName());
//	}
//
//	@Test
//	public void testSimpleDelete() {
//	      Clazz clz = entityManager.find(Clazz.class, 4);
//	      Set<Student> stus = clz.getStus();
//	      stus.forEach((stu) -> stu.setClazz(null));
//	      entityManager.remove(clz);
//	}
//	
//	//--------四种状态--------
//	@Test
//	public void testPersist() {
//		Grade grade = new Grade();
//		grade.setName("一年级");
//		grade.setNumber(3);
//		entityManager.persist(grade);// 转换为托管状态
//
//		grade.setName("一年级-1");
//		//结果：“一年级-1”
//	}
//	
//	@Test
//	public void testMerge() {
//		Grade grade = new Grade();
//		grade.setName("一年级");
//		grade.setNumber(3);
//		entityManager.merge(grade);
//
//		grade.setName("一年级-1");
//		//结果：“一年级”
//	}
//	
//	@Test
//	public void testMerge2() {
//		Grade grade = new Grade();
//		grade.setName("一年级");
//		grade.setNumber(3);
//		Grade grade_new = entityManager.merge(grade);
//
//		grade_new.setName("一年级-1");
//		//结果：“一年级-1”
//	}
//	
//	@Test
//	public void testDetach() {
//		Grade grade = entityManager.find(Grade.class, 1);//托管态
//		entityManager.detach(grade);//变成游离态
//		//clear也可以，是把整个上下文中托管态的都变成游离态，所以要慎用
//		//entityManager.clear();
//		grade.setName("一年级-1");
//		entityManager.merge(grade);//能提交到数据库，但grade依然是游离态
//		grade.setName("一年级-2");//无法自动更新数据
//		//结果：“一年级-1”
//	}
//	
//	@Test
//	public void testRemove() {
//		Grade grade = entityManager.find(Grade.class, 1);//托管态
//		entityManager.remove(grade);//变为删除态，如果此时就提交事务结束，数据库中对应的数据就删除了
//		entityManager.persist(grade);//就像上图所示的，通过persist，删除态再次变为托管态，此时提交事务就不会删除了
//	}
//	
//	@Test
//	public void testMerge3() {
//		Student stu = new Student();
//		stu.setName("aaa");
//		stu.setId(17);
//		entityManager.merge(stu);
//	}
//	
//	@Test
//	public void testPersist2() {
//		Student stu = new Student();
//		stu.setName("aaa");
//		stu.setId(17);
//		entityManager.persist(stu);
//	}
//	
//	@Test
//	public void testPersist3() {
//		Student stu = entityManager.find(Student.class, 17);
//		entityManager.detach(stu);//变为游离态
//		entityManager.persist(stu);//游离态不能persist
//	}
//	
//	//--------懒加载--------
//	public void testFetch_lazzy() {
//		Student stu = entityManager.find(Student.class, 1);//A. 只查询了Student表
//		Clazz clz = stu.getClazz();//B. 这里虽然getClazz，也没有触发查询Clazz表，因为并没有真正使用
//		String clzName = clz.getName();//C. 触发查询Clazz表
//	}
//	
//	//--------级联操作--------
//	@Test
//	public void testCascadeCreate() {
//	  Clazz clz1 = new Clazz();
//      clz1.setName("计科1601");
//      clz1.setDate(new Date());
//      
//      Student stu1 = new Student();
//      stu1.setName("mary");
//      stu1.setTel("18866005544");
//      stu1.setDate(new Date());
//      stu1.setClazz(clz1);
//      
//      //设置了实体级联持久化，clazz作为student的子实体可以被级联持久化
//      //entityManager.persist(clz1);//不再需要先持久化clz1
//      entityManager.persist(stu1);
//	}
//	
//	@Test
//	public void testCascadeDelete() {
//	      Clazz clz = entityManager.find(Clazz.class, 1);
//	      //删除clz就把级联的student也都删除掉了
//	      entityManager.remove(clz);
//	}
//	
//	//--------JPQL--------
//	@Test
//	public void testDynamicQuery() {
//		String jpql = "select d from Student d";
//		Query query = entityManager.createQuery(jpql);
//		List list = query.getResultList();//返回结果列表
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	
//	@Test
//	public void testStaticQuery() {
//		Query query = entityManager.createNamedQuery("Student.findMyTel");
//		query.setParameter("myTel", "18866005544");//动态添加参数
//		List list = query.getResultList();//返回结果列表
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	
//	@Test
//	public void testDynamicQuery_delete() {
//		//和一般sql没什么区别，注意参数建议动态添加，可以防止sql注入，不要自己拼接
//		String jpql_delete = "delete from Student d where d.id=:p_id";
//		Query query = entityManager.createQuery(jpql_delete);
//		query.setParameter("p_id", 3);//动态添加参数
//		int result = query.executeUpdate();//返回值代表成功处理了几条数据
//		System.out.println(result);
//	}
//	
//	@Test
//	public void testDynamicQuery_update() {
//		//和一般sql没什么区别，注意参数建议动态添加，可以防止sql注入，不要自己拼接
//		String jpql_update = "update Student d set d.name=:p_name where d.tel=:p_tel";
//		Query query = entityManager.createQuery(jpql_update);
//		query.setParameter("p_name", "mary2");//动态添加参数
//		query.setParameter("p_tel", "1312213123");
//		int result = query.executeUpdate();//返回值代表成功处理了几条数据
//		System.out.println(result);
//	}
//	
//	@Test
//	public void testDynamicQuery_where_between() {
//		String jpql_where_between = "select d from Student d where d.id between 4 and 6";
//		Query query = entityManager.createQuery(jpql_where_between);
//		List list = query.getResultList();//返回结果列表。 注意前后都是包括边界的[4, 6]
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	
//	@Test
//	public void testDynamicQuery_where_in() {
//		String jpql_where_in = "select d from Student d where d.id in(4, 6)";
//		Query query = entityManager.createQuery(jpql_where_in);
//		List list = query.getResultList();//返回结果列表。 注意前后都是包括边界的[4, 6]
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	
//	@Test
//	public void testDynamicQuery_where_like() {
//		String jpql_where_like = "select d from Student d where d.name like '%mary%'";
//		Query query = entityManager.createQuery(jpql_where_like);
//		List list = query.getResultList();//返回结果列表。 注意前后都是包括边界的[4, 6]
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	
//	@Test
//	public void testDynamicQuery_aggre_count() {
//		String jpql_aggre_count = "select count(d) from Student d";
//		Query query = entityManager.createQuery(jpql_aggre_count);
//		Long result = (Long) query.getSingleResult();//注意返回值是Long，直接转成Integer是会报错的
//		System.out.println(result);
//	}
//	
//	@Test
//	public void testDynamicQuery_aggre_max() {
//		String jpql_aggre_max = "select max(d.id) from Student d";
//		Query query = entityManager.createQuery(jpql_aggre_max);
//		Integer result = (Integer)query.getSingleResult();
//		System.out.println(result);
//	}
//	
//	@Test
//	public void testDynamicQuery_aggre_min() {
//		String jpql_aggre_min = "select min(d.id) from Student d";
//		Query query = entityManager.createQuery(jpql_aggre_min);
//		Integer result = (Integer)query.getSingleResult();
//		System.out.println(result);
//	}
//	
//	@Test
//	public void testDynamicQuery_order() {
//		String jpql_order = "select d from Student d order by d.date desc";
//		Query query = entityManager.createQuery(jpql_order);
//		List list = query.getResultList();//返回结果列表
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	
//	@Test
//	public void testDynamicQuery_join() {
//		//错误写法
//		//String jpql_join = "select d from Student d left join Clazz c where d.clz_id=c.id and c.name='计科1601'";
//		String jpql_join = "select d.name, d.clazz.name from Student d left join d.clazz where d.clazz.name='计科1601'";
//		Query query = entityManager.createQuery(jpql_join);
//		List<Object[]> list = query.getResultList();//返回结果列表
//		for (Object[] obj : list) {
//			System.out.println(obj[0] + ", " + obj[1]);
//		}
//	}
//	
//	@Test
//	public void testDynamicQuery_distinct() {
//		String jpql_distinct = "select distinct d.name from Student d";
//		Query query = entityManager.createQuery(jpql_distinct);
//		List<String> list = query.getResultList();//返回结果列表
//		for (String obj : list) {
//			System.out.println(obj);
//		}
//	}
//	
//	@Test
//	public void testDynamicQuery_page() {
//		int pageSize = 3;
//		int pageNow = 2;
//		
//		String jpql = "select d from Student d";
//		Query query = entityManager.createQuery(jpql);
//		query.setMaxResults(pageSize);//设置页长pageSize
//		query.setFirstResult(pageSize * (pageNow - 1));//设置起始页,从0开始
//		
//		List list = query.getResultList();//返回结果列表
//		for (Object obj : list) {
//			System.out.println(((Student)obj).getName());
//		}
//	}
//	
//	@Test
//	public void testNativeQuery() {
//		String jqpl = "select * from t_student";
//		Query query = entityManager.createNativeQuery(jqpl);
//		List<Object[]> list = query.getResultList();//返回值是一个数组集合
//		for (Object[] arr : list) {
//			System.out.println(arr[0] + ", " + arr[1] + ", " + arr[2] + ", " + arr[3]);
//		}
//		
//	}
//	
	//--------标准(Criteria)API--------
//	@Test
//	public void testCriteriaAPI_select() {
//		//1. 前后的步骤和前面的一样，只不过CriteriaAPI不直接使用entityManager，而是使用CriteriaBuilder
//		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
//		//2. 构建一个查询对象
//		CriteriaQuery<Student> cq = cb.createQuery(Student.class);
//		//3. 从CriteriaQuery对象的方法调用来设置查询根
//		Root<Student> stu = cq.from(Student.class);
//		cq.where(cb.greaterThan(stu.get("id"), 7));
//		
//		//4. 调用CriteriaQuery对象的select()方法来指定查询结果的类型
//		CriteriaQuery<Student> select = cq.select(stu);
//		
//		//5. 最后还是用entityManager创建查询, 返回值和jpql不太一样的是，
//		//这里返回的是一个带泛型的接口，也就是说是直接指定返回类型的数据
//		TypedQuery<Student> query = entityManager.createQuery(select);
//		List<Student> list = query.getResultList();
//		
//		for (Student st : list) {
//			System.out.println(st.getName());
//		}
//	}
//	
//	//--------事务--------
//	public void testMethod() {
//		Student stu_find = entityManager.find(Student.class, 17);//托管态
//		System.out.println(stu_find.getId());
//		//虽然已经是托管态，但jpa还没有智能到随时感知到数据库的变化,毕竟是两个独立的系统，所以需要refresh一下
//		//有些人可能要说，为什么在使用persist新增数据时(用merge就不行)，可以马上获取到数据库新增的id，那是因为jpa知道
//		//你设置的id生成策略，知道新增数据时 数据库要新生成一个id，所以能获取到数据库自增长的id也不奇怪（具体怎么获取的我也不知道）
//		entityManager.refresh(stu_find);//在这一行打上断点。然后去数据库 手动修改一下数据库中的student.name
//		System.out.println(stu_find.getName());
//	}
	
	
}
